<template>
  <div 
    ref="rootRef"
    :class="[
      'bx-image',
      'bx-glass',
      {
        'bx-image--round': round,
        'bx-image--lazy': lazyLoad
      }
    ]"
    :style="imageStyle"
  >
    <img 
      v-if="!hasError && !loading"
      :src="currentSrc"
      :alt="alt"
      :style="objectFitStyle"
      @load="handleLoad"
      @error="handleError"
    />
    <div v-if="loading" class="bx-image__loading">
      <slot name="loading">
        <BxLoading size="small" />
      </slot>
    </div>
    <div v-if="hasError" class="bx-image__error">
      <slot name="error">
        <BxIcon name="image-off" />
        <p>加载失败</p>
      </slot>
    </div>
    <div v-if="$slots.placeholder" class="bx-image__placeholder">
      <slot name="placeholder"></slot>
    </div>
  </div>
</template>

<script>
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import BxLoading from '../data-display/BxLoading.vue'
import BxIcon from '../basic/BxIcon.vue'

export default {
  name: 'BxImage',
  components: {
    BxLoading,
    BxIcon
  },
  props: {
    src: {
      type: String,
      default: ''
    },
    alt: {
      type: String,
      default: ''
    },
    width: {
      type: [String, Number],
      default: 'auto'
    },
    height: {
      type: [String, Number],
      default: 'auto'
    },
    fit: {
      type: String,
      default: 'cover',
      validator: (value) => ['fill', 'contain', 'cover', 'none', 'scale-down'].includes(value)
    },
    round: {
      type: Boolean,
      default: false
    },
    lazyLoad: {
      type: Boolean,
      default: false
    },
    placeholderSrc: {
      type: String,
      default: ''
    }
  },
  emits: ['load', 'error'],
  setup(props, { emit }) {
    const loading = ref(true)
    const hasError = ref(false)
    const currentSrc = ref(props.lazyLoad ? props.placeholderSrc : props.src)
    const rootRef = ref(null)

    const imageStyle = computed(() => ({
      width: typeof props.width === 'number' ? `${props.width}px` : props.width,
      height: typeof props.height === 'number' ? `${props.height}px` : props.height
    }))

    const objectFitStyle = computed(() => ({
      objectFit: props.fit
    }))

    const handleLoad = (event) => {
      loading.value = false
      hasError.value = false
      emit('load', event)
    }

    const handleError = (event) => {
      loading.value = false
      hasError.value = true
      emit('error', event)
    }

    const loadImage = () => {
      if (props.src) {
        loading.value = true
        hasError.value = false
        const img = new Image()
        img.src = props.src
        img.onload = () => {
          currentSrc.value = props.src
          handleLoad()
        }
        img.onerror = () => {
          handleError()
        }
      }
    }

    const handleIntersection = (entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          loadImage()
          // 停止观察，避免重复加载
          if (observer.value) {
            observer.value.unobserve(entry.target)
          }
        }
      })
    }

    let observer = ref(null)

    onMounted(() => {
      if (props.lazyLoad && rootRef.value) {
        observer.value = new IntersectionObserver(handleIntersection, {
          rootMargin: '0px',
          threshold: 0.1
        })
        observer.value.observe(rootRef.value)
      } else {
        loadImage()
      }
    })

    onUnmounted(() => {
      if (observer.value) {
        observer.value.disconnect()
      }
    })

    watch(() => props.src, (newSrc) => {
      if (!props.lazyLoad) {
        loadImage()
      }
    })

    return {
      loading,
      hasError,
      currentSrc,
      imageStyle,
      objectFitStyle,
      handleLoad,
      handleError,
      rootRef
    }
  }
}
</script>

<style scoped>
.bx-image {
  display: inline-block;
  position: relative;
  overflow: hidden;
  border-radius: var(--bx-radius-medium);
  background: var(--bx-glass-bg);
  backdrop-filter: var(--bx-glass-blur);
  font-family: var(--bx-font-family);
}

.bx-image--round {
  border-radius: 50%;
}

.bx-image img {
  display: block;
  width: 100%;
  height: 100%;
}

.bx-image__loading,
.bx-image__error,
.bx-image__placeholder {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--bx-text-tertiary);
  font-size: 14px;
  background: rgba(0, 0, 0, 0.1);
}

.bx-image__error .bx-icon {
  font-size: 24px;
  margin-bottom: 8px;
}

.bx-image__error p {
  margin: 0;
}
</style>

